package utils

import (
	"strconv"
	"strings"
)

// 变量能使用的字符
var variableNameCharacter = []rune("_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")

// 判断字符串是否符合变量命名规则
func IsVariableNameRule(str string) bool {
	for _, r := range []rune(str) {
		var isVariableNameCharacter = false
		for _, v := range variableNameCharacter {
			if v == r {
				isVariableNameCharacter = true
				break
			}
		}
		if !isVariableNameCharacter {
			return false
		}
	}
	return true
}

// 删除括号中的内容包括括号
// 删除前: a.name.show(123,1).name1.show12(123,1,show12.show(123,1))
// 删除后: a.name.show.name1.show12
func DelBrackets(str string) string {
	//找最后一个左括号
	leftIndex := 0
	rightIndex := 0
	for i := len(str) - 1; i >= 0; i-- {
		if string(str[i]) == "(" {
			leftIndex = i
			break
		}
	}
	//从左括号开始找第一个右括号
	for i := leftIndex; i < len(str); i++ {
		if string(str[i]) == ")" {
			rightIndex = i
			break
		}
	}
	//删除左右括号中的内容
	str = str[:leftIndex] + str[rightIndex+1:]
	//递归删除括号中的内容
	if strings.Contains(str, "(") {
		str = DelBrackets(str)
	}
	return str
}

//	函数括号中的内容,替换为占位符
//
// 删除前: a.name.show(123,1).name1.show12(123,1,show12.show(123,1))
// 删除后: a.name.show.@@FuncBracket1.name1.show12.@@FuncBracket2
func FuncBracketsReplace(str string) (map[string]string, string) {
	//判断括号个数是否相等
	leftCount := strings.Count(str, "(")
	rightCount := strings.Count(str, ")")
	if leftCount != rightCount {
		panic(str + "函数括号不匹配")
	}
	var mapUnite = make(map[string]string)
	leftIndex := 0
	rightIndex := 0
	for i := len(str) - 1; i >= 0; i-- {
		if string(str[i]) == "(" {
			leftIndex = i
			break
		}
	}
	//从左括号开始找第一个右括号
	for i := leftIndex; i < len(str); i++ {
		if string(str[i]) == ")" {
			rightIndex = i
			break
		}
	}
	if leftIndex == 0 && rightIndex == 0 {
		return mapUnite, str
	}
	//将括号中的内容替换为占位符
	var uniteStr = "@@FuncBracket" + strconv.Itoa(leftIndex) + RandStringRunes()
	mapUnite[uniteStr] = "(" + str[leftIndex+1:rightIndex] + ")"
	str = str[:leftIndex] + uniteStr + str[rightIndex+1:]
	//递归删除括号中的内容
	if strings.Contains(str, "(") {
		var mapUnite2 map[string]string
		mapUnite2, str = FuncBracketsReplace(str)
		for k, v := range mapUnite2 {
			mapUnite[k] = v
		}
	}
	return mapUnite, str
}

// 将占位符替换为函数表达式
func FuncBracketsReplaceBack(mapUnite map[string]string, str string) string {
	for k, v := range mapUnite {
		str = strings.Replace(str, k, v, -1)
	}
	return str
}

// 拆分调用链,返回一个数组
func SplitCallChain(content string) []string {
	contentdel := DelBrackets(content) //去掉括号
	var tokens []string
	//以点为分隔符,分割字符串
	split := strings.Split(contentdel, ".")

	//还原括号
	for i := 0; i < len(split)-1; i++ {
		token := split[i+1]
		//截取下一个token之前的内容
		index := strings.Index(content, token)
		if index != 0 {
			tokens = append(tokens, content[:index-1])
			content = content[index:]
			continue
		} else {
			//遇到两个连续的调用并且名称相同的情况,如a.show().show() ,解决办法就是先把第一个show去掉获,然后获取show在加上show的长度
			//获取show的长度
			showLen := len(token)
			//截取下一个token之前的内容
			content11 := content[showLen:]
			//获取show的位置
			index = strings.Index(content11, token)
			index = index + showLen
			tokens = append(tokens, content[:index-1])
			content = content[index:]
		}

	}
	//获取最后一个token位置
	tokens = append(tokens, content)
	return tokens
}

// 将函数表达式替换成占位符,并返回替换后的字符串和函数表达式map
func FuncExpressionReplace(str string) (map[string]string, string) {
	var mapFunc = make(map[string]string)
	for i := 1; i < len(str); i++ {
		//判断是否是函数
		if str[i] == '(' && IsVariableNameRule(string(str[i-1])) {
			var startIndex int
			var endIndex int
			var num = 1
			//向左找直到不等于正则表达式\w
			for j := i - 1; j >= 0; j-- {
				if !IsVariableNameRule(string(str[j])) {
					startIndex = j + 1
					break
				}
			}
			//向右找到)的位置
			for j := i + 1; j < len(str); j++ {
				if str[j] == '(' {
					num++
				}
				if str[j] == ')' {
					num--
				}
				if num == 0 {
					endIndex = j
					break
				}
			}
			//截取函数
			var funcStr = str[startIndex : endIndex+1]
			var key = "@@func" + strconv.Itoa(i) + RandStringRunes()
			//使用占位符funci替换
			str = str[:startIndex] + key + str[endIndex+1:]
			//将函数放入map中
			mapFunc[key] = funcStr
		}
	}
	return mapFunc, str
}

// 将函数调用参数切割为数组
func SplitFuncParams(str string) []string {
	mapFunc, s1 := FuncExpressionReplace(str)
	//将字符串替换成占位符
	replace, s2 := StrReplace(s1)
	//将s1以逗号分割
	split := strings.Split(s2, ",")
	var result []string
	//将字符串替换回来
	for _, v := range split {
		v = StrRestore(v, replace)
		result = append(result, v)
	}

	//将函数表达式替换回来
	for i, v := range result {
		for k, v1 := range mapFunc {
			if strings.Contains(v, k) {
				v = strings.ReplaceAll(v, k, v1)
				result[i] = v
			}
		}
	}

	return result
}

// //将字符串替换成占位符@@str,并返回替换后的字符串和字符串map
func StrReplace(str string) (map[string]string, string) {
	var mapStr = make(map[string]string)
	for i := 0; i < len(str); i++ {
		//判断是否是字符串
		if str[i] == '"' {
			var startIndex int = i
			var endIndex int
			var num = 1
			//向右找到下一个"
			for j := i + 1; j < len(str); j++ {
				if str[j] == '"' {
					num--
				}
				if num == 0 {
					endIndex = j
					break
				}
			}
			if endIndex == 0 {
				//如果没有找到,则直接返回
				break
			}
			//截取字符串
			var newStr = str[startIndex : endIndex+1]
			//使用占位符funci替换
			var key = "@@str" + strconv.Itoa(i) + RandStringRunes()
			str = str[:startIndex] + key + str[endIndex+1:]
			//将字符串放入map中
			mapStr[key] = newStr
		}
	}
	return mapStr, str
}

// 还原字符串
func StrRestore(str string, mapStr map[string]string) string {
	for k, v := range mapStr {
		str = strings.ReplaceAll(str, k, v)
	}
	return str
}

// 提取注解名称和注解参数
func ExtractAnnotation(str string) (string, map[string]string) {
	var mapParams = make(map[string]string)
	//去掉@
	str = str[1:]
	//截取第一个(之前的内容
	index := strings.Index(str, "(")
	//获取注解名称
	name := str[:index]
	//获取注解参数
	params := str[index+1 : len(str)-1]
	//替换字符串
	maps, s1 := StrReplace(params)
	funcParams := strings.Split(s1, ",") //将参数转换为数组
	//将注解参数转换为map
	for i := range funcParams {
		//获取一个=位置
		index = strings.Index(funcParams[i], "=")
		//如果是-1那么就没有参数,我们就默认给一个value
		if index == -1 {
			mapParams["value"] = funcParams[i]
			continue
		}
		//获取参数名称
		paramName := funcParams[i][:index]
		//获取参数值
		paramValue := funcParams[i][index+1:]
		//将字符串替换回来
		paramValue = StrRestore(paramValue, maps)
		//去掉两边的"
		paramValue = strings.Trim(paramValue, "\"")
		//将参数放入map中
		mapParams[paramName] = paramValue
	}
	return name, mapParams
}

// 获取字符串下标
func GetStrIndex(str1 string, str2 string) int {
	//str转字符数组
	var str1r = []rune(str1)
	var str2r = []rune(str2)
	//获取str2的长度
	str2Len := len(str2r)
	//获取str1的长度
	str1Len := len(str1r)
	for i := 0; i < str1Len; i++ {
		//判断是否越界
		if i+str2Len-1 > str1Len {
			return -1
		}
		//截取str1的内容
		str1r1 := str1r[i : i+str2Len]
		//判断是否相等
		if string(str1r1) == string(str2r) {
			return i
		}
	}
	return -1
}

// 获取字符串最后一个下标
func GetStrLastIndex(str1 string, str2 string) int {
	//str转字符数组
	var str1r = []rune(str1)
	var str2r = []rune(str2)
	//获取str2的长度
	str2Len := len(str2r)
	//获取str1的长度
	str1Len := len(str1r)
	for i := str1Len - 1; i >= 0; i-- {
		//判断是否越界
		if str2Len-1 > str1Len {
			return -1
		}
		//截取str1的内容
		str1r1 := str1r[i : i+str2Len]
		//判断是否相等
		if string(str1r1) == string(str2r) {
			return i
		}
	}
	return -1
}

// 截取字符串内部${}的变量
func GetStrBigBrackets(str string) ([]string, bool) {
	//判断是否有${}
	if strings.Index(str, "${") == -1 || strings.Index(str, "}") == -1 {
		return nil, false
	}
	//判断{}是否成对出现
	if strings.Count(str, "{") != strings.Count(str, "}") {
		panic("字符串中的{}不成对出现")
	}
	var result []string
	var num = 0
	var startIndex = 0
	var endIndex = 0
	for i := 0; i < len(str); i++ {
		if string(str[i]) == "$" && string(str[i+1]) == "{" {
			num++
			if num == 1 {
				startIndex = i + 1
			}
		}
		if string(str[i]) == "}" {
			num--
			if num == 0 {
				endIndex = i
				result = append(result, str[startIndex+1:endIndex])
			}
		}
	}
	return result, true
}
